/* $RCSFile: CountryTable.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/Country/CountryTable.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:28  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Xml;
using System.Globalization;

using AddonNice.Diagnostics;

namespace AddonNice.Country
{
	/// <summary>
	/// CountryTable is an handy class that abstracts 
	/// and caches the Country list
	/// </summary>
	internal class CountryTable
	{
		private static CountryInfo[] _countryTable;
		private static CountryInfo[] _inhabitedCountryTable;

        static CountryStoreResources _CountryStoreResources    =   new CountryStoreResources();

		private static void InitializeStore()
		{
            if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable InitializeStore _countryTable null:{0}, _inhabitedCountryTable null:{1}",(_countryTable == null),(_inhabitedCountryTable == null)),CountryTraceSwitch.Sw.Info);
			if (_countryTable == null)
			{
				lock (typeof(CountryTable))
					if (_countryTable == null) 
					{
						_countryTable = _CountryStoreResources.GetCountries(CountryTypes.AllCountries);
					}
			}

			if (_inhabitedCountryTable == null)
			{
				lock (typeof(CountryTable))
					if (_inhabitedCountryTable == null) 
					{
						_inhabitedCountryTable = getUninhabitedCountries();
					}
			}
		}

		private static CountryInfo[] getUninhabitedCountries()
		{
			ArrayList inhabitedCountries = new ArrayList();
			foreach(CountryInfo c in _countryTable)
			{
				if (c.Inhabited == true)
					inhabitedCountries.Add(c);
			}
			return (CountryInfo[]) inhabitedCountries.ToArray(typeof(CountryInfo));
		}

		internal static CountryInfo GetCountryInfoFromName(string Name)
		{
            if (_countryTable == null)
                InitializeStore();
			return RecurseGetCountryInfoFromName(Name, _countryTable);		
		}

		internal static CountryInfo RecurseGetCountryInfoFromName(string Name, CountryInfo[] c)
		{
		    if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable RecurseGetCountryInfoFromName Name: {0}, CountryInfo[] is null:{1}",Name,(c == null)),CountryTraceSwitch.Sw.Info);
            if (c == null)
                return null;
			for (int i = 0; i < c.Length; i++)
			{
                CountryInfo ci   =   c[i];
		        if ( CountryTraceSwitch.Sw.TraceVerbose )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable RecurseGetCountryInfoFromName Name: {0}, c[{1}].Name: {2}",Name,i,ci.Name),CountryTraceSwitch.Sw.Info);
				if (Name.Equals(ci.Name) || Name.Equals(ci.ThreeLetterISOCountryName) || Name.Equals(ci.EnglishName))
				{
		            if ( CountryTraceSwitch.Sw.TraceVerbose )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable RecurseGetCountryInfoFromName found Name: {0}, c[{1}].Name: {2}",Name,i,ci.Name),CountryTraceSwitch.Sw.Info);
					return ci;
				}

				if (ci.Childs != null)
				{
					CountryInfo cci = RecurseGetCountryInfoFromName(Name, ci.Childs);
					if (cci != null)
					{
						return cci;
					}
				}
			}
	        if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable RecurseGetCountryInfoFromName Name: {0} not found",Name),CountryTraceSwitch.Sw.Info);
			return null;
		}

		/// <summary>
		/// Gets the list of supported cultures filtered by the specified CountryTypes.
		/// </summary>
		internal static CountryInfo[] GetCountries(CountryTypes types, CountryFields sortBY)
		{
			if (_countryTable == null)
				InitializeStore();

			CountryInfo[] countryTable;
	        if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable GetCountries types: {0}, sortBY: {1}",types,sortBY),CountryTraceSwitch.Sw.Info);

			switch (types)
			{
				case CountryTypes.InhabitedCountries:
					countryTable = _inhabitedCountryTable;
					break;

				default:
				case CountryTypes.AllCountries:
					countryTable = _countryTable;
					break;
			}
            
			//Sort it
			sortCountries(countryTable, sortBY);

			return countryTable;
		}

		public static CountryInfo[] GetCountriesFiltered(string filter, CountryFields sortBY)
		{
			if (_countryTable == null)
				InitializeStore();
	        if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable GetCountriesFiltered filter: {0}, sortBY: {1}",filter,sortBY),CountryTraceSwitch.Sw.Info);

			System.Collections.ArrayList filteredCountries  =   new System.Collections.ArrayList();

			string[] countryNames                           =   filter.Split(new char[]{';'},StringSplitOptions.RemoveEmptyEntries);

			foreach(string countryName in countryNames)
			{
				// CS 31/10/04 added for safety
				try
				{
					CountryInfo ci	                        =   new CountryInfo(countryName);
					filteredCountries.Add(ci);
				}
				catch(Exception ex)
				{
					if ( CountryTraceSwitch.Sw.TraceError )
                        System.Diagnostics.Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"GetCopuntriesFiltered countryName:{0}, ex:{1}",countryName,ex),CountryTraceSwitch.Sw.Info);
				}
			}

			CountryInfo[] countryTable                      = (CountryInfo[]) filteredCountries.ToArray(typeof(CountryInfo));
            
			sortCountries(countryTable, sortBY);

			return countryTable;
		}

		public static SortedList<string,CountryInfo> GetDicCountriesFiltered(string filter, CountryFields sortBY)
		{
			if (_countryTable == null)
				InitializeStore();
	        if ( CountryTraceSwitch.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]CountryTable GetCountriesFiltered filter: {0}, sortBY: {1}",filter,sortBY),CountryTraceSwitch.Sw.Info);

		    SortedList<string,CountryInfo> filteredCountries    =   new SortedList<string,CountryInfo>();
			string[] countryNames                               =   filter.Split(new char[]{';'},StringSplitOptions.RemoveEmptyEntries);

			foreach(string countryName in countryNames)
			{
				try
				{
					CountryInfo ci	                            =	new CountryInfo(countryName);
                    switch (sortBY)
                    {
                        case CountryFields.Name:
                            filteredCountries.Add(ci.Name, ci);
                            break;
                        case CountryFields.None:
                        case CountryFields.DisplayName:
                            filteredCountries.Add(ci.DisplayName, ci);
                            break;
                        case CountryFields.EnglishName:
                            filteredCountries.Add(ci.EnglishName, ci);
                            break;
                    }
				}
				catch(Exception ex)
				{
					if ( CountryTraceSwitch.Sw.TraceError )
                        System.Diagnostics.Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"GetCopuntriesFiltered countryName: {0}, ex: {1}",countryName,ex),CountryTraceSwitch.Sw.Info);
				}
			}
			return filteredCountries;
		}

        private static void sortCountries(CountryInfo[] countryTable, CountryFields sortBY)
		{
			//Sort it
			switch (sortBY)
			{
				case CountryFields.Name:
					Array.Sort(countryTable, new CountryInfoNameComparer());
					break;

				case CountryFields.DisplayName:
					Array.Sort(countryTable, new CountryInfoDisplayNameComparer());
					break;

				case CountryFields.EnglishName:
					Array.Sort(countryTable, new CountryInfoEnglishNameComparer());
					break;

				case CountryFields.None:
				default:
					//No sort
					break;
			}
		}
	}
}